/*
 * TinyWiki View & Edit - v0.1.0
 *  Copyright 2010 - 2011, itozyun
 *  Released under the MIT, BSD, and GPL Licenses.
 */
// ---------------------------------------------------
// jQuery extend
//
	$.fn.extend({
		addPage: function( data){
			// thisがnavi内のulでない return
			
			var li = wiki.edit.naviTemplete();
			if( !data.children){
				li.removeClass( 'sm_liOpen');
				li.find( 'dd.sm_expander').remove();
				li.children( 'ul').remove();
			} else {
				if( !data.open){
					li.removeClass( 'sm_liOpen').addClass( 'sm_liClosed');
				} else {
					li.removeClass( 'sm_liClosed').addClass( 'sm_liOpen');
				}
				li.find( '.sm_expander').text( li.hasClass( 'sm_liOpen') ? String.fromCharCode( 9660) : String.fromCharCode( 9658));				
			}
			this.append( li);
			 
			var page = wiki.edit.pageTemplete();
			page.attr( 'id', data.id);
			$( '#content').append( page);

			li.updatePage( data);
			
			if( wiki.isEdit){
				li.editStart();
			}
			wiki.view.setFocus( data.id);
			
			return li.children( 'ul');
		},
		updatePage: function( data){
			var dl = this.children( 'dl');
			var a = dl.find( 'a');
			a.text( data.title || a.text());
			
			var oldID = a.fingerPageID() || data.id;
			a.attr( 'href', '#' +data.id);

			var page = $( '#' +oldID).attr( 'id', data.id);
			page.children( '.page-title').text( data.title);
			page.children( '.page-body').html( data.content);
			var pageData = page.children( '.page-data');
			
			pageData.find( '.page-creator').text( data.creator || wiki.owner);
			pageData.find( '.page-pubdate').text( wiki.util.createDate( data.pubdate));
			pageData.find( '.page-update').text( wiki.util.createDate( data.update));		
		},
		editStart: function(){
			// thisがnavi内のliでない return
		// add dd.dropzone
			var dl = this.children( 'dl');
			if( dl.children( 'dd.dropzone').length === 0){
				dl.prepend( '<dd class="dropzone"></dd>');
			}
		// drop
			dl.children( 'dt,dd.dropzone').droppable({
		        accept: '#sitemap li',
		        tolerance: 'pointer',
		        drop: function( e, ui) {
					var li = $( this).parent().parent();
					if( $( this).hasClass( 'dropzone')) {
						li.before( ui.draggable);  
					} else {
					    li.getChildrenContainer( true).append( ui.draggable);
					}
					li.children( 'dl').children( 'dt, dd.dropzone').css({ backgroundColor: ''});
					
					setTimeout( function(){ // 時間差をつけないとクローンページができてしまう
						wiki.doc.trigger( wiki.event.WIKI_CLEANUP_EVENT);
						wiki.doc.trigger( wiki.event.WIKI_DATA_UPDATE_EVENT);								
					}, 0);

		        },
		        over: function() {
		            $( this).filter( 'dt').css( { backgroundColor: '#ccc'});
		            $( this).filter( 'dd.dropzone').css( { backgroundColor: '#aaa'});
		        },
		        out: function() {
		            $( this).css( { backgroundColor: ''});
		        }
		    });
			
		// drag
			if( this.attr( 'id') !== wiki.trashID){
				this.draggable({
			        handle: ' > dl',
			        opacity: .8,
			        addClasses: false,
			        helper: 'clone',
			        zIndex: 100// ,start: function(e, ui) {}
			    });				
			}
		},
		getChildrenContainer: function( open){
			if( this.children( 'ul').length === 0) {
                this.append( '<ul></ul>');
            }
			var dl = this.children( 'dl');
			if( dl.find( 'dd.sm_expander').length === 0){
				dl.children( 'dt').before( '<dd class="sm_expander"></dd>');
			}	
			if( open){
				this.addClass( 'sm_liOpen').removeClass( 'sm_liClosed');
			} else {
				this.removeClass( 'sm_liOpen').addClass( 'sm_liClosed');
			}
			return this.children( 'ul');
		},
		parentPage: function(){
			if( !this){
				return undefined;
			}
			return this.parent();
		},
		fingerPageID: function(){
			if( this.attr( 'href')){
				var a = this;
			} else {
				var a = this.children( 'dl').find( 'a');
			}
			if( a.length === 0){
				return undefined;
			}
			return ( a.attr( 'href') || '').replace( /.*#(.*)/, '$1');
		},
		delPage: function(){
			// thisがnavi内のliでない return
			if( $( this, wiki.view.navi()).length === 0){
				return;
			}
			var li = this;
			li.slideUp( 'normal', function(){// スライドして削除
				if( li.children('ul')) { // 子の繰上げ
					var ul = li.parent();
					var insIndex = $( 'li', ul).index( li);
					
					li.children( 'ul').children( 'li').each( function( i, el){
						if( ul.children( 'li').length -1 > insIndex) {
							ul.children().eq( insIndex +i).after( el);
						} else {
							ul.append( el);
						}
					});
				}
				wiki.edit.trash().append( li.show());
				
				wiki.doc.trigger( wiki.event.WIKI_CLEANUP_EVENT);
				wiki.doc.trigger( wiki.event.WIKI_DATA_UPDATE_EVENT);
			});
		},
		showPage: function( data){
			
		},
		pageData: function(){
			// thisがnavi内のliでない return
			
			var id = this.fingerPageID();
			var dataArray = wiki.view.dataArray();
			var l = dataArray.length;
			for( var i=0; i<l; i++){
				if( dataArray[ i].id === id){
					return dataArray[ i];
				}
			}
			return false;
		}
	});
	
// ---------------------------------------------------
// wiki
//
	var wiki = wiki || {};
	
	wiki.baseUrl = (function(){
		var ary = location.pathname.split( '\/');
		return ary[ ary.length -1];
	})();

	wiki.urlParams = (function(){
		var ret = {};
		var params = location.search.split( '&');
		var l = params.length;
		for(var i=0; i<l; i++){
			var param = params[ i].split( '=');
			if( param.length === 2){
				ret[ param[ 0]] = decodeURIComponent( param[ 1]);
			}
		}
		return ret;
	})();
	
	wiki.updating = false;
	wiki.data = undefined;
	wiki.isEdit = ( wiki.urlParams.edit == 1);
	wiki.trashID = 'trash-li';
	wiki.doc = undefined;
	wiki.user = {};
	
	wiki.event = {
		GET_WIKI_DATA_COMPLETE_EVENT:	'getWikiDataComplete',
		EDIT_WIKI_START_EVENT:			'editWikiStart',
		EDIT_SETTING_START_EVENT:		'editSettingStart',
		EDITOR_POPUP_EVENT:				'editPageStart',
		CREATE_PAGE_COMPLETE_EVENT:		'createPageCompleteEvent',
		WDIT_PAGE_COMPLETE_EVENT:		'editPageCompleteEvent',
		LIST_DATA_UPDATE_EVENT:			'listDataUpdate',
		WIKI_DATA_UPDATE_EVENT:			'wikiDataUpdate',
		WIKI_CLEANUP_EVENT:				'wikiCleanUp'
	};
	
	wiki.util = {
		createDate: function( utc){
			if( utc === undefined){
				return '';
			}
			function toDouble(n){
				n += '';
				return ( n.length === 1) ? '0' + n : n;
			}
			var d = new Date();
			d.setTime( utc);
			return [
				d.getFullYear(),
				'\/',
				toDouble( d.getMonth() +1),
				'\/',
				toDouble( d.getDate()),
				' ',
				toDouble( d.getHours()),
				':',
				toDouble( d.getMinutes()),
				':',
				toDouble( d.getSeconds())
			].join( '');

		}
	}
	
// ---------------------------------------------------
// wiki core
//
	wiki.core = (function(){
		var list, data, index, id,
			userId = gadgets.util.getUrlParameters().userId || gadgets.util.getUrlParameters().id || '@viewer';	;
		
		function getWikiData( _id){
			id = _id;
			if( id){
				wiki.updating = true;
				//addClass('ui-state-ajax');
				
				var batch = osapi.newBatch();
				batch.add('user', osapi.people.getViewer({fields: 'activity'}))
					//.add('listData', osapi.appdata.get({ data: 'list'}))
					.add('appData', osapi.appdata.get({ userId: userId, groupId: '@self', appId: '@app', keys: [ 'list', id ] }))
					//.add('wikiData', osapi.people.getViewer({fields: 'appdata.' + id}))
					.execute( getWikiDataComplete);
			}
		}
		function getWikiDataComplete( response){
			wiki.user = response.user;
			var	appData = response.appData,
				wikiData = response.appData;
			
			//header.removeClass('ui-state-ajax');
			wiki.updating = false;
			
			if ( appData && !appData.error && appData.list) {
				data = (function(){
					var ret = {};
					list = appData.list || [];
					
					var l = list.length;
					for (var i = 0; i < l; i++) {
						ret = list[i];
						if (ret.id === id) {
							break;
						}
					}
					ret.body = appData[ id] || {};
					// Listに無い場合
					return ret;
				})();
				
				wiki.doc.trigger( wiki.event.GET_WIKI_DATA_COMPLETE_EVENT, data);
			
			}
			// wiki.social.sendMsg			
		}
		
		return {
			init: function(){
				wiki.doc = $( document);
				wiki.doc.bind( wiki.event.WIKI_DATA_UPDATE_EVENT, wiki.core.updateWiki)
						.bind( wiki.event.LIST_DATA_UPDATE_EVENT, wiki.core.updateList);
				
				id = wiki.urlParams.wikiId;
				
				wiki.view.init();
				wiki.edit.init();
				getWikiData( id);
				
				if( wiki.isEdit){
					wiki.doc.trigger( wiki.event.EDIT_WIKI_START_EVENT);	
				}			
			},
			updateList: function(){
				//header.addClass('ui-state-ajax');
				wiki.updating = true;
				osapi.appdata.update({ data: {list: list} }).execute( function(response) {
					//header.removeClass('ui-state-ajax');
					wiki.updating = false;
					
					if( response.error) {
						alert('__MSG_OOPS__' + '__MSG_HTTP_FORBIDDEN__');
						return false;
					}
					// wiki.social.sendMsg
				});
			},
			updateWiki: function(){
				//header.addClass('ui-state-ajax');
				
				var update = {};
				update[ id] = {
					children: 	buildData( [], wiki.view.navi()),
					history:	{}
				};
				
				function buildData(_data, _ul){
					_ul.children('li').each(function(i, el){
						var li = $(this);
						if( li.attr( 'id') !== wiki.trashID){
							var _pageData = li.pageData();
							if (_pageData) {
								delete _pageData.children;
								_data.push(_pageData);
								if ( li.children('ul').length > 0 && li.find('li').length > 0) { //$.childPages()
									_pageData.children = [];
									if (li.hasClass('sm_liOpen')) {
										_pageData.open = true;
									} else {
										delete _pageData.open;
									}
									buildData( _pageData.children, li.children('ul'));
								}
							}							
						}
					});
					return _data;
				}				
				
				wiki.updating = true;
				
				osapi.appdata.update( { data: update}).execute( function(response) {
					//header.removeClass('ui-state-ajax');
					wiki.updating = false;
					
					if( response.error) {
						alert('__MSG_OOPS__' + '__MSG_HTTP_FORBIDDEN__');
						return false;
					}
					// wiki.social.sendMsg
				});
			}		
		}
	})();
// ---------------------------------------------------
// wiki view
//	
	wiki.view = ( function(){
		var	focusPageID,
			navi,
			pageContainer,
			dataArray = [],
			data, body;
		
		function buildWiki( e, _data){
			data = _data;
			body = data.body || {};
	
			buildWikiTitle();
			
			if( body.children && body.children.length > 0){
				buildPage( navi, body.children);
				focusPageID = (function(){
					var ret = location.hash.replace( /#/, '');
					return ( $( '#' +ret).length !== 0) ? ret : changeFocus();
				})();			
				hilight();
			} else {
				body.children = [];
			}
			
			wiki.doc.trigger( wiki.event.WIKI_CLEANUP_EVENT);
			if( wiki.isEdit){
				//wiki.edit.start();
				if( !data.title){
					wiki.doc.trigger( wiki.event.EDIT_SETTING_START_EVENT);
				} else	
				if( dataArray.length === 0){
					wiki.edit.createNewPage();
				}
			}
		}
		function buildPage( ul, datas){
			var l = datas.length;
			for( var i=0; i<l; i++){
				var data = datas[ i];
				if( data.id && data.title && data.content){
					if( data.children){
						buildPage( ul.addPage( data), data.children);
					} else {
						ul.addPage( data);
					}
					dataArray.push( data);					
				}
			}			
		}
		
		function buildWikiTitle(){
			if( data.title){
				$( 'h1').text( data.title);
			}
			if( data.footer){
				$( '#footer').text( data.footer);
			}
		}
		function changeFocus( id){
			id = id || '';
			if( id !== ''){
				navi.find( '#trash').find( 'a').each( function( i, el){
					if( $( this).fingerPageID() === id){
						id = '';
						return false;
					}
				});
			}
			if( id === '' || !document.getElementById( id)){
				var li = navi.find( 'li:eq(0)');
				if( li.attr( 'id') !== wiki.trashID){
					id = li.fingerPageID();
				}
			}		
			focusPageID = document.location.hash = id || '';
			
			if( id !== ''){
				$( '#content-control').css( { display: 'block'}); //bind
			}
			
			hilight();
			return id;
		}
		function hilight(){
			navi.find( 'dl').css( { backgroundColor: ''});
			if( focusPageID && focusPageID !== ''){
				focusPageLi().children( 'dl').css( { backgroundColor: '#ddf'});
			}
		}
		function setToggle( expander, ncr){ //Numeric character reference
			expander = $( expander);
			var li = expander.parent().parent();
			if( li.find( 'li').length !== 0){
				if( li.hasClass( 'sm_liOpen')){
					expander.text( ncr ? '&#9660;' : String.fromCharCode( 9660));
					li.pageData().open = true;
				} else {
					expander.text( ncr ? '&#9658;' : String.fromCharCode( 9658));
					delete li.pageData().open;
				}
			} else {
				expander.text( '');
			}
		}
		function focusPageLi(){
			var ret;
			navi.find( 'a').each(function(i, el){
				var a = $( this);
				if( a.fingerPageID() === focusPageID) {
					ret = a.parent().parent().parent(); //a > dt > dl >li
					return false;
				}
			});
			return ret;
		}
		function cleanUp(){
			wiki.view.naviClean();
			changeFocus();
			wiki.view.updateToggle( false);
		}
		return {
			init: function(){
				navi = $( '#sitemap');
				pageContainer = $( '#content');
				wiki.doc.bind( wiki.event.GET_WIKI_DATA_COMPLETE_EVENT, buildWiki);
				wiki.doc.bind( wiki.event.WIKI_CLEANUP_EVENT, cleanUp);
				wiki.doc.bind( wiki.event.LIST_DATA_UPDATE_EVENT, buildWikiTitle);
				
			// expand	
				navi.find( 'dd.sm_expander').live( 'click', function() {
					$( this).parent().parent().toggleClass( 'sm_liOpen').toggleClass( 'sm_liClosed');
					setToggle( this, false);
					wiki.doc.trigger( wiki.event.WIKI_DATA_UPDATE_EVENT);
				});
			
			// click focus
				navi.find( 'a').live( 'click', function() {
					changeFocus( $( this).fingerPageID());
					return false;
				});
			},
			addPage: function( newPageData, _ul){
				_ul = _ul || navi;
				_ul.addPage( newPageData);
				dataArray.push( newPageData);
				
				wiki.doc.trigger( wiki.event.WIKI_DATA_UPDATE_EVENT);
			},
			updatePage: function( updatePageData, _li){
				_li = _li || focusPageLi();
				_li.updatePage( updatePageData);
				
				wiki.doc.trigger( wiki.event.WIKI_DATA_UPDATE_EVENT);
			},
			getfocusPageID: function(){
				return focusPageID || '';
			},
			getfocusPageData: function(){
				var li = focusPageLi();
				return li ? li.pageData() : undefined;
			},
			getfocusPageLi: focusPageLi,
			setFocus: changeFocus,
			setToggle: function( expander, ncr){
				setToggle( expander, ncr);
			},
			updateToggle: function( ncr){
				navi.find( '.sm_expander').each( function( i, el){
					setToggle( this, ncr);
				});
			},
			dataArray: function(){
				return dataArray
			},
			pageCount: dataArray.length,
			navi: function(){
				return navi;
			},
			pageContainer: function(){
				return pageContainer;
			},
			naviClean: function(){
				navi.find( 'li').each( function( i, el){
					var li = $( el);
					var ul = li.children( 'ul');
					if( ul.children( 'li').length === 0){
						ul.remove();
						li.find( 'dd.sm_expander').remove();
					}
				});
			}
		}
	})();

// ---------------------------------------------------
// wiki editor
//
	wiki.edit = (function(){
		var	trash,
			naviTemplete,
			pageTemplete,
			editConsole,
			settingConsole;

		function start(){
		// add Page
			$('#addNewPage').click( wiki.edit.createNewPage);				
			
			$( '#content').before(
				$( [
					'<div id="content-control" style="display:none;">',
						'<div id="editPage" class="button button-1st">EDIT</div>',
						'<div id="delPage" class="button button-last">DEL</div>',
					'</div>'
				].join( ''))
			);

		// delete Page
			$('#delPage').click( function(){
				var id = wiki.view.getfocusPageID();
				if( id && id !== '' && $( '#' +id).length !== 0) {
					( wiki.view.getfocusPageLi()).delPage();
				}
			});
		// edit Page
			$( '#editPage').click( function(){
				var data = wiki.view.getfocusPageData();
				if( data){
					editConsole.popup( data, true);
				}
			});
		}
			
		return {
			init: function(){
				naviTemplete = $( $( '#naviTemplate').html());
				pageTemplete = $( $( '#pageTemplate').html());

				editConsole = wiki.editor();
				settingConsole = wiki.setting();

				wiki.doc.bind( wiki.event.EDIT_WIKI_START_EVENT, start);
				wiki.doc.bind( wiki.event.EDIT_SETTING_START_EVENT, settingConsole.show);
			},
			naviTemplete: function(){
				return naviTemplete.clone();
			},
			pageTemplete: function(){
				return pageTemplete.clone();
			},
			trash: function(){
				if( !trash){
					var trashContainer = $( $( '#trashTemplate').html()).attr( 'id', wiki.trashID);
					wiki.view.navi().append( trashContainer);
					trashContainer.editStart();
					trash = $( '#trash');
				}
				return trash;
			},
			createNewPage: function(){
				editConsole.popup( {
					title:		'newTitle',
					id:			'id' +( new Date()).getTime(),
					content:	'content'
				}, false);
				//wiki.edit.beforeJump( true);				
			},
			beforeJump: function( sw){
				if( sw){
					if( !window.onbeforeunload){
						window.onbeforeunload = function( e){
							e = e || window.event;
							return e.returnValue = '編集中ですが移動してよいですか？';
						}
					}
				} else {
					window.onbeforeunload = function(){};
					window.onbeforeunload = undefined;
				}
			}
		}
	})();



/* -----------------------------------
 *  wiki editor
 */
	wiki.editor = function(){
		var	console = $( '#pageEditor'),
			editor,
			isEdit,
			title = $( '#editTitle'),
			id = $( '#editID'),
			content = $( '#editContent'),
			errTitle = $( '#editorErrTitle'),
			errID = $( '#editorErrID');

		function eraceErrMsg(){
			errTitle.text( '');
			errID.text( '');				
		}
		function check( data){
			var c = ( data.title && data.title !== '');
			if( !c){
				errTitle.text( 'タイトルを入力してください。');
			}
			
			var _id = data.id || '';
			var msg = ( _id && _id !== '') ? [] : [ 'IDを入力してください'];
			
			if(
				( !isEdit && ( $( '#' +_id).length !== 0)) ||
				( isEdit && wiki.view.getfocusPageID() !== _id && $( '#' +_id).length !== 0)
			){
				msg.push( 'IDが重複しています。edit' +isEdit +' id:' +_id );
			}
			if( _id.match( /[^\w-]/)){
				msg.push( '半角英数字とハイフン(-)以外は使えません。');
			}
			if( !_id.match( /^[A-Za-z]/)){
				msg.push( '最初の文字は英字にしてください。');
			}
			if( msg.length > 0){
				errID.text( msg.join( '<br>'));
				return false;
			}
			return  c;
		}
		function close(){
			console.hide();
		}
		
		return {
			popup: function( data, _isEdit){
				console.show();
				if( editor === undefined){
					editor = new nicEditor( { fullPanel: true}).panelInstance( 'editContent');
					$( '#publishBtn').click( function(){
						eraceErrMsg();
						
						data.title = title.val();
						data.id = id.val();
						data.content = editor.instanceById('editContent').getContent();
						
						var d = ( new Date()).getTime();
						
						if( check( data)){
							if( isEdit){
								data.update = d;
								wiki.view.updatePage( data, null);
							} else {
								data.pubdate = d;
								data.creator = wiki.user.displayName;
								var li = wiki.view.getfocusPageLi();
								wiki.view.addPage( data, li ? li.parentPage() : wiki.view.navi());
							}
							close();
						}
					});
					$( '#cancelBtn').click( close);
				}
				title.val( data.title);
				id.val( data.id);
				content.val( data.content);
				isEdit = _isEdit;
				editor.instanceById( 'editContent').setContent( data.content);
				
				eraceErrMsg();
			},
			eraceErrMsg: eraceErrMsg
		}
	};

// ---------------------------------------------------
// wiki.setting
//
	wiki.setting = function(){
		var	data,
			console = $( '#wikiSettingConsole'),
			title = $( '#editWikiTitle'),
			description = $( '#editWikiDescription'),
			footer = $('#editWikiFooter');

		$( '#setPublishBtn').click( function (){
			close();
			
			data.title = title.val();
			data.description = description.val();
			data.footer = footer.val();
			
			wiki.doc.trigger( wiki.event.LIST_DATA_UPDATE_EVENT);
		});
		$( '#setCancelBtn').click( close);
		
		function close(){
			console.hide();
		}
		
		return {
			show: function( _data){
				data = _data;
				if( data.title){
					title.attr( 'value', data.title);
				}
				if( data.description){
					description.attr( 'value', data.description);
				}	
				if( data.footer){
					footer.attr( 'value', data.footer);
				}
				console.show();
			}
		}
	};
		
	gadgets.util.registerOnLoadHandler( wiki.core.init);
	gadgets.util.runOnLoadHandlers();
	